package newcommerce.media
{
	import newcommerce.events.MediaEvent;
	import flash.events.EventDispatcher;
	import newcommerce.data.AbstractMediaData;
	import newcommerce.data.MediaData;
	import flash.display.Sprite;
    import flash.events.IOErrorEvent;
	import flash.events.Event;
	import flash.events.ProgressEvent;
	import flash.events.TimerEvent;
    import flash.media.Sound;
    import flash.media.SoundChannel;
	import flash.media.SoundLoaderContext;
	import flash.media.SoundTransform;
    import flash.net.URLRequest;
	import flash.utils.Timer;
	import flash.system.LoaderContext;
	
	public class MP3Player extends EventDispatcher
	{
		// queue of Track objects
		protected static var _instance:MP3Player;
		
		protected var _song:SoundChannel;
		protected var _soundFactory:Sound;
		protected var _currentMedia:MediaData;
		protected var _mute:Boolean = false;
		
		/**
		* SoundTransform is used to change the volume of the playing stream
		*/		
		protected var _soundTransform:SoundTransform;
		
		protected var _timer:Timer;
		protected var _playing:Boolean = false;
		protected var _currentPos:Number = 0;	
		protected var _pct:Number = 0;
		protected var _lastVolume:Number = 0.5;
		protected var _paused:Boolean = false;
		protected var _fullyLoaded:Boolean = false;
		
		public function get volume():Number
		{
			return _lastVolume*100;
		}
		
		public function get paused():Boolean
		{
			return _paused;
		}
		
		public function get position():Number
		{
			if(_song != null)
				return Math.round(_song.position/1000);
			else
				return 0;
		}
		
		public function get duration():Number
		{
			return _fullyLoaded ? ((_currentMedia != null) ? _currentMedia.duration : -1)  : -1;
		}
		
		public function get currentMedia():MediaData { return _currentMedia; }		
		
		public static function getInstance():MP3Player
		{
			if(_instance == null)
				_instance = new MP3Player();

			return _instance;
		}
		
		public function MP3Player()
		{
			createSoundFactory();
			_soundTransform = new SoundTransform();
			
			_timer = new Timer(500);
			_timer.addEventListener(TimerEvent.TIMER, monitorPosition);
			//_timer.start();
		}
		
		public function playMedia(media:AbstractMediaData):void
		{
			_currentMedia = media as MediaData;
			if(isPlaying())
				stop();
				
			play(true);
		}
		
		/**
		* Mute or unmute the stream
		* @param	muted boolean flag
		*/
		public function mute(muted:Boolean):void
		{
			//trace("mute("+muted+")");
			_mute = muted;
			if(_mute)
			{
				_soundTransform.volume = 0;
				_song.soundTransform = _soundTransform;
			}
			else
			{
				_soundTransform.volume = _lastVolume;
				_song.soundTransform = _soundTransform;
			}
		}
		/**
		* set the volume level (0 to 100)
		* @param	volume (0 to 100)
		*/
		public function setVolume(volume:Number):void
		{		
			if(_soundTransform != null)
			{
				_lastVolume = _soundTransform.volume = volume/100;
			
				if(!_mute && _song != null)
					_song.soundTransform = _soundTransform;
			}
			else
			{
				trace("soundTransform was null!");
			}
		}
	
		public function stop():void
		{
			_playing = false;
			_paused = false;
			if(_song != null)
			{
				_song.stop();
				try
				{
					_soundFactory.close();
				}
				catch(err:Error)
				{
					trace(err);
				}
				
			}
			
			_timer.stop();
			_timer = new Timer(500);
			_timer.addEventListener(TimerEvent.TIMER, monitorPosition);
			
			_currentPos = 0;
		}
		
		protected function createSoundFactory():void
		{
			if(_soundFactory != null)
			{
				try{
					_soundFactory.close();
				}
				catch(err:Error)
				{
					
				}
						
				_soundFactory.removeEventListener(Event.COMPLETE, doComplete);
				_soundFactory.removeEventListener(Event.ID3, doId3);
				_soundFactory.removeEventListener(IOErrorEvent.IO_ERROR, doIoError);
				_soundFactory.removeEventListener(ProgressEvent.PROGRESS, doProgress);
			}
			
			_soundFactory = new Sound();
			_soundFactory.addEventListener(Event.COMPLETE, doComplete);
            _soundFactory.addEventListener(Event.ID3, doId3);
            _soundFactory.addEventListener(IOErrorEvent.IO_ERROR, doIoError);
            _soundFactory.addEventListener(ProgressEvent.PROGRESS, doProgress);
			_fullyLoaded = false;
		}


		public function play(newTrack:Boolean = false):void
		{	
			//trace("mp3player.play("+newTrack+")");
			if(_playing)
				pause();	
			
			if(newTrack)
			{
				var loaderContext:SoundLoaderContext = new SoundLoaderContext(1000, true);
				
				//trace("MP3Player -- loading track:"+_currentMedia.uri);
				var request:URLRequest = new URLRequest(_currentMedia.uri);
				createSoundFactory();
				
				_soundFactory.load(request, loaderContext);
				_song = _soundFactory.play(0, 0, _soundTransform);
			}
			else
			{
				_song = _soundFactory.play(_currentPos, 0, _soundTransform);
				_currentPos = 0;
			}
			
			_playing = true;
			_paused = false;
			
			_timer.start();
		}
		
		public function seek(pos:Number):void
		{
			if(_paused)
			{
				_song = _soundFactory.play(pos*1000, 0, _soundTransform);
				pause();
			}
			else
			{
				_song.stop();			
				_song = _soundFactory.play(pos*1000, 0, _soundTransform);
			}
		}
		
		public function isPlaying():Boolean
		{
			return _playing;
		}

		public function pause():void
		{
			//trace("mp3Player.pause");
			if(_song != null)
			{
				//trace("stopping song");
				_paused = true;
				_currentPos = _song.position;
				_song.stop();
			}
		}

        protected function doComplete(event:Event):void 
		{
			//trace("mp3player.doComplete -- soundFactory.length:"+(_soundFactory.length/1000)+" seconds");
			//_currentMedia.duration = Math.round(_soundFactory.length/1000);
			_fullyLoaded = true;
			dispatchEvent(new MediaEvent(MediaEvent.MEDIA_DURATION, {duration:_currentMedia.duration}));
        }

        protected function doId3(event:Event):void {
           // trace("id3Handler: " + event);
        }

        protected function doIoError(event:Event):void
		{
            trace("ioErrorHandler: " + event);
			trace("couldn't load:"+_currentMedia.uri);
			dispatchEvent(new MediaEvent(MediaEvent.INVALID_MEDIA, {}));
        }

        protected function doProgress(event:ProgressEvent):void {
           // trace("progressHandler: " + event);
			_pct = Math.round(event.bytesLoaded / event.bytesTotal * 100);
			dispatchEvent(new MediaEvent(MediaEvent.MEDIA_LOAD_PROGRESS, {loaded:_pct}));
        }

		public function getSongPosition():Number
		{
			return Math.round(_song.position);
		}

		protected function monitorPosition(event:TimerEvent):void
		{
			if(_song != null)
			{
				dispatchEvent(new MediaEvent(MediaEvent.MEDIA_TIME, {seconds:Math.round(_song.position/1000), loaded:_pct}));
				
				if(_song.position == 0 && _soundFactory.bytesLoaded > _soundFactory.bytesTotal/9 && _timer.currentCount > 30)
				{
					dispatchEvent(new MediaEvent(MediaEvent.INVALID_MEDIA, {}));
					stop();
				}
				
				if(_fullyLoaded && _song.position/1000 >= _currentMedia.duration-1)
				{
					stop();
					_fullyLoaded = false;
					dispatchEvent(new MediaEvent(MediaEvent.MEDIA_FINISHED_PLAYING, {media:_currentMedia}));
				}
			}
        }

		public function isBuffering():Boolean
		{
			return _soundFactory.isBuffering;
		}
	}
}